#include "../games/globale.h" // Fonction et Headers globaux
#include "../games/cls_configuration.h" // Classe de gestion du fichier de configuration
#include "../objects/cls_objet.h" // objet du décors

/* ----------------------------------------------------
			Constructeur
  ----------------------------------------------------- */
cls_Objet::cls_Objet()
{
    debugTrace("Constructeur cls_Objet");

    // Initialisation des surfaces
    this->p_sdlS_ImageObjet = NULL;
    //this->paramObjet2 = NULL;

    // La souris n'est pas sur l'objet
    this->isMouseOver=false;
    // Et pas conséquent elle n'y etait pas avant
    this->wasMouseOverBefore=false;

    // Initialisation de nextUpdateTime
    this->n_NextUpdateTime = 0;

}

/* ----------------------------------------------------
			Destructeur
  ----------------------------------------------------- */
cls_Objet::~cls_Objet()
{
    debugTrace("Destructeur cls_Objet");
}



/* ----------------------------------------------------
			Retourne le position en X et en Y
			ainsi que la taille de l'objet
  ----------------------------------------------------- */
    int cls_Objet::fct_GetPosX() { return this->sdlR_PositionObjet_XY.x;}
    int cls_Objet::fct_GetPosY() { return this->sdlR_PositionObjet_XY.y;}
    int cls_Objet::fct_GetHeight() { return this->n_CST_ObjetHeight;}
    int cls_Objet::fct_GetWidth() { return this->n_CST_ObjetWidth;}


/* ----------------------------------------------------
			Détermine si la condition est valide ou non
  ----------------------------------------------------- */
bool cls_Objet::fct_IsConditionValide(string stConditionObject)
{
    vector<string> VecStrComposanteCondition;
    vector<string> VecStrSplitComposante;

    bool flgResultat;
    string tempo;

    flgResultat=true;

    if (strTrim(stConditionObject) != "*")
    {
        // On récupère les différentes composantes de la condition
        // -> [EVT_001=TRUE] & [EVT_002=TRUE]
        VecStrComposanteCondition.clear();
        strSplit(stConditionObject, VecStrComposanteCondition, "&");

        // Pour toutes ces composantes
        // -> [EVT_002=TRUE]
        for(unsigned int i(0); i<VecStrComposanteCondition.size(); i++)
        {
            // On sépare le nom et la valeur
            // EVT_002 et TRUE
            tempo = strTrim(VecStrComposanteCondition[i]);
            VecStrSplitComposante.clear();
            strSplit(tempo.substr(1, tempo.length() - 2), VecStrSplitComposante, "=");

            // On va vérifié dans les évènements du scénario
            for(unsigned int j(0); j<this->clsScenario->t_valEvenement.size(); j++)
            {
                // Si le nom correspond
                if (this->clsScenario->t_valEvenement[j].st_Nom == VecStrSplitComposante[0])
                {
                    // On vérifie si la valeur de la condition et celle de l'évènement correspondent
                    if ((this->clsScenario->t_valEvenement[j].isActive == true && VecStrSplitComposante[1] == "FALSE") || (this->clsScenario->t_valEvenement[j].isActive == false && VecStrSplitComposante[1] == "TRUE"))
                    {
                        // Si elles ne correspondent pas le retour est faux !!
                        flgResultat=false;
                    }
                }
            }

        }
    }
    return flgResultat;
}

/* ----------------------------------------------------
			Calcul de la position relative de l'objet
  ----------------------------------------------------- */
void cls_Objet::fct_CalculPositionRelative()
{

// Gestion du décalage de la map
    // Si l'objet est en entier dans la fenêtre (bord gauche et bord droit)
    if (this->n_PositionABS_x - this->clsMap_Encours->sdlR_PositionMap_Decalage.x >= 0
        && (this->n_PositionABS_x + this->n_CST_ObjetWidth) - this->clsMap_Encours->sdlR_PositionMap_Decalage.x <= cls_Configuration::getWindowWidth())
    {
        this->sdlR_PositionObjet_XY.x = this->n_PositionABS_x - this->clsMap_Encours->sdlR_PositionMap_Decalage.x;
        this->sdlR_PositionObjet_Decalage.x = 0;
        this->sdlR_PositionObjet_Decalage.w = this->n_CST_ObjetWidth;
    }
    // BORD GAUCHE
    // Si l'objet est coupé par le bord gauche
    else if (this->n_PositionABS_x - this->clsMap_Encours->sdlR_PositionMap_Decalage.x > -this->n_CST_ObjetWidth
        && this->n_PositionABS_x - this->clsMap_Encours->sdlR_PositionMap_Decalage.x < 0)
    {
        this->sdlR_PositionObjet_XY.x = 0;
        this->sdlR_PositionObjet_Decalage.x = -(this->n_PositionABS_x - this->clsMap_Encours->sdlR_PositionMap_Decalage.x);
        this->sdlR_PositionObjet_Decalage.w = this->n_CST_ObjetWidth-(this->n_PositionABS_x - this->clsMap_Encours->sdlR_PositionMap_Decalage.x);
    }
    // Si l'objet n'est plus visible par le bord gauche
    else if (this->n_PositionABS_x - this->clsMap_Encours->sdlR_PositionMap_Decalage.x <= -this->n_CST_ObjetWidth)
    {
        this->sdlR_PositionObjet_XY.x = 0;
        this->sdlR_PositionObjet_Decalage.x = 0;
        this->sdlR_PositionObjet_Decalage.w = 0;
    }
    // BORD DROIT
    // Si l'objet est coupé par le bord droit
    else if ((this->n_PositionABS_x + this->n_CST_ObjetWidth) - this->clsMap_Encours->sdlR_PositionMap_Decalage.x < cls_Configuration::getWindowWidth() + this->n_CST_ObjetWidth
        && (this->n_PositionABS_x + this->n_CST_ObjetWidth) - this->clsMap_Encours->sdlR_PositionMap_Decalage.x > cls_Configuration::getWindowWidth())
    {
        this->sdlR_PositionObjet_XY.x = this->n_PositionABS_x - this->clsMap_Encours->sdlR_PositionMap_Decalage.x;
        this->sdlR_PositionObjet_Decalage.x = 0;
        this->sdlR_PositionObjet_Decalage.w = (cls_Configuration::getWindowWidth() + this->n_CST_ObjetWidth) -((this->n_PositionABS_x + this->n_CST_ObjetWidth) - this->clsMap_Encours->sdlR_PositionMap_Decalage.x);
    }
    // Si l'objet n'est plus visible par le bord droit
    else if ((this->n_PositionABS_x + this->n_CST_ObjetWidth) - this->clsMap_Encours->sdlR_PositionMap_Decalage.x >= cls_Configuration::getWindowWidth() + this->n_CST_ObjetWidth)
    {
        this->sdlR_PositionObjet_XY.x = cls_Configuration::getWindowWidth();
        this->sdlR_PositionObjet_Decalage.x = 0;
        this->sdlR_PositionObjet_Decalage.w = 0;
    }

}


/* ----------------------------------------------------
			On charge l'image de l'objet
  ----------------------------------------------------- */
void cls_Objet::fct_InitObjet(cls_Mouse * clsMouse_Encours, cls_Scenario* clsScenario, cls_Dialog* clsDialog, cls_Map * clsMap_Encours, cls_PrimitiveTexte * clsPrimTexte_DescObj, StrucObjets * paramObjet)
{

    // Initialisation des paramètres
    this->clsMouse_Encours = clsMouse_Encours;
    this->clsMap_Encours = clsMap_Encours;
    this->clsPrimTexte_DescObj = clsPrimTexte_DescObj;
    this->clsDialog = clsDialog;
    this->clsScenario = clsScenario;
    this->paramObjet = paramObjet;

    // Taille de l'objet
    this->n_CST_ObjetWidth = paramObjet->n_ObjetWidth;
    this->n_CST_ObjetHeight = paramObjet->n_ObjetHeight;

    // Position par défaut
    this->n_PositionABS_x = paramObjet->n_DefaultX;
    this->n_PositionABS_y = paramObjet->n_DefaultY;

    // Image de l'objet
    this->p_sdlS_ImageObjet = load_image(join_pathFile(PATH_DATA_IMG_OBJECTS, paramObjet->st_FileName));

    // Valeur par defaut
    this->sdlR_PositionObjet_XY.x = this->n_PositionABS_x;
    this->sdlR_PositionObjet_XY.y = this->n_PositionABS_y;
    this->sdlR_PositionObjet_XY.w = this->n_CST_ObjetWidth;
    this->sdlR_PositionObjet_XY.h = this->n_CST_ObjetHeight;
    this->sdlR_PositionObjet_Decalage.x = 0;
    this->sdlR_PositionObjet_Decalage.y = 0;
    this->sdlR_PositionObjet_Decalage.w = this->n_CST_ObjetWidth;
    this->sdlR_PositionObjet_Decalage.h = this->n_CST_ObjetHeight;

    // On fait les decalages necessaires pour positionné l'objet
    // aux coordonnées relatives
    fct_CalculPositionRelative();

}


/* ----------------------------------------------------
    Gestion des évènements d'un object
    On passe dans la fonction [fct_HandleInput] dans chaque classes : cls_map, cls_personnage, cls_object
  ----------------------------------------------------- */
void cls_Objet::fct_HandleInput(SDL_Event event)
{
    switch (event.type)
    {
        // Lors du Mouse_UP
        case SDL_MOUSEBUTTONUP:
            // Si l'on est au dessus de l'object en cours
            // Bouton Gauche : On execute l'action
            // Bouton Droit : On change l'action
            if (isInBox(this->sdlR_PositionObjet_XY, event.motion.x, event.motion.y) == true)
            {
                switch (event.button.button)
                {
                    case SDL_BUTTON_LEFT:
                        //debugTrace("###############  BTN G ############");
                        break;

                    case SDL_BUTTON_RIGHT:
                        // On passe à l'action suivante
                        this->clsMouse_Encours->fct_GetNextActionCursor();
                        this->clsMouse_Encours->fct_SetMouseCursor(this->clsMouse_Encours->fct_GetCurrentActionCursor());
                        // On réinitialise le flag de présence lors de l'affichage précédent
                        // car on a demandé un changement d'action.
                        this->wasMouseOverBefore=false;
                        break;
                }
            }
            break;

        // Lors du Mouse_MOVE
        case SDL_MOUSEMOTION:
            // Si l'on est au dessus de l'object en cours
            // On vient dessiner le curseur d'action courant
            if (isInBox(this->sdlR_PositionObjet_XY, event.motion.x, event.motion.y) == true)
            {
                this->isMouseOver=true;
                this->clsMouse_Encours->fct_SetMouseCursor(this->clsMouse_Encours->fct_GetCurrentActionCursor());
            }
            else
            {
                // Si on quitte l'objet, on réinitialise la flag de la souris
                this->isMouseOver=false;
                this->wasMouseOverBefore=false;
            }
            break;

        default: break;
    }


}


/* ----------------------------------------------------
			On Dessine l'image de l'objet au bon endroit
  ----------------------------------------------------- */
void cls_Objet::fct_DrawObjet(SDL_Surface *p_sdlS_Ecran, int n_CurrentTime)
{

    //char stMsgDescription[256];
    bool evtValide;
    vector<StrucCondition> objStuctCondition;
    string LibelleAction;
    string stCorrespondance;

    // Si on a dépassé la "date" de mise à jour du sprite, on passe à l'étape suivante de l'animation
    if(n_CurrentTime > this->n_NextUpdateTime)
    {
        // On fait les decalages necessaires pour positionné l'objet
        // aux coordonnées relatives
        fct_CalculPositionRelative();

        // On fixe la date du prochain changement : une demi seconde après
        this->n_NextUpdateTime = n_CurrentTime + this->clsMap_Encours->getMapDelai();

        // Si la souris est sur l'objet, on affiche le texte jusqu'au prochain reaffichage
        if (this->isMouseOver)
        {
            // Si on était déjà présent avec la même action sur le même objet,
            // On récupère le message de la dernière fois
            if ( ! this->wasMouseOverBefore)
            {
                // On récupère la tableau contenant les informations sur les
                // conditons de l'action correspondante au curseur de souris
                // en cours
                objStuctCondition.clear();
                switch (this->clsMouse_Encours->fct_GetCurrentActionCursor())
                {
                    case MOUSE_CURSOR_INFO:
                        LibelleAction=LIB_ACTION_INFO;
                        objStuctCondition=this->paramObjet->actionLook;
                        break;
                    case MOUSE_CURSOR_OPEN:
                        LibelleAction=LIB_ACTION_OPEN;
                        objStuctCondition=this->paramObjet->actionOpen;
                        break;
                    case MOUSE_CURSOR_CLOSE:
                        LibelleAction=LIB_ACTION_CLOSE;
                        objStuctCondition=this->paramObjet->actionClose;
                        break;
                    case MOUSE_CURSOR_TAKE:
                        LibelleAction=LIB_ACTION_TAKE;
                        objStuctCondition=this->paramObjet->actionTake;
                        break;
                    case MOUSE_CURSOR_USE:
                        LibelleAction=LIB_ACTION_USE;
                        objStuctCondition=this->paramObjet->actionUse;
                        break;
                    case MOUSE_CURSOR_TALK:
                        LibelleAction=LIB_ACTION_TALK;
                        objStuctCondition=this->paramObjet->actionTalk;
                        break;
                }


                // Initialisation des différents objets
                evtValide=false;
                // Pour toutes les possibilitées de l'action en cours de cet objet
                for(unsigned int i(0); i<objStuctCondition.size(); i++)
                {
                    // Si on n'a pas encore trouvé le cas ou la condition est valide
                    if (evtValide == false)
                    {
                        // On demande une vérification de la condition
                        if (fct_IsConditionValide(objStuctCondition[i].st_Condition) == true)
                        {
                        // Si la condition respecte les "EVENEMENTS" définit...
                            // On recherche la correspondance du code
                            stCorrespondance=clsDialog->FindCorrespondance(strTrim(objStuctCondition[i].st_Description));
                            sprintf(this->stMsgDescription, "%s %s", LibelleAction.c_str(), stCorrespondance.c_str());
                            // ... et c'est gagné !!!
                            evtValide=true;
                        }
                    }
                }
            }

            // Retourne le texte suivant les conditions
            this->clsPrimTexte_DescObj->fct_DefineTexte(this->stMsgDescription, this->n_NextUpdateTime);

            // Pour le prochain passage, la souris sera notée comme déjà présente la fois précédente !!
            this->wasMouseOverBefore=true;
        }
    }
    SDL_BlitSurface(this->p_sdlS_ImageObjet, &this->sdlR_PositionObjet_Decalage, p_sdlS_Ecran, &this->sdlR_PositionObjet_XY);

}


/* ----------------------------------------------------
			On libere l'image de fond
  ----------------------------------------------------- */
void cls_Objet::fct_FreeSurface()
{
    SDL_FreeSurface(this->p_sdlS_ImageObjet);

    // Joda du 15/01/2008
/*
    free(this->clsMouse_Encours);
    free(this->clsMap_Encours);
    free(this->clsPrimTexte_DescObj);
*/
}
